#pragma once

#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <functional>

#include "log.hpp"
#include "ThreadPool.hpp"
#include "InetAddr.hpp"
using namespace log_ns;

enum
{
    SOCK_ERROR = 1,
    BIND_ERROR,
    LISTEN_ERROR,
};

const static uint16_t gport = 8888;
const static int gsockfd = -1;
const static int gbacklog = 8;

using task_t = std::function<void()>;

using handler_t = std::function<std::string(const std::string &)>;

class TcpServer
{
public:
    TcpServer(handler_t handler, uint16_t port = gport)
        : _handler(handler), _port(port), _listen_sockfd(gsockfd), _is_running(false)
    {}

    void init_server()
    {
        // 1.创建套接字
        _listen_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
        if (_listen_sockfd < 0)
        {
            LOG(FATAL, "socket error!\n");
            exit(SOCK_ERROR);
        }
        LOG(INFO, "socket create success!\n");

        // 2. bind sockfd 和 sockaddr
        struct sockaddr_in addr;
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_port = htons(_port);
        addr.sin_addr.s_addr = INADDR_ANY;
        if (::bind(_listen_sockfd, (struct sockaddr *)&addr, sizeof(addr)))
        {
            LOG(FATAL, "bind error!\n");
            exit(BIND_ERROR);
        }
        LOG(INFO, "bind success!\n");

        // 3. 由于tcp是面向连接的，所以需要不断的获取连接
        if (::listen(_listen_sockfd, gbacklog) < 0)
        {
            LOG(FATAL, "listen error!\n");
            exit(LISTEN_ERROR);
        }
        LOG(INFO, "listen success!\n");
    }

    class ThreadData
    {
    public:
        ThreadData(TcpServer *self, int sockfd, const InetAddr &addr) : _sockfd(sockfd), _self(self), _addr(addr)
        {
        }
        ~ThreadData()
        {
        }

    public:
        TcpServer *_self;
        int _sockfd;
        InetAddr _addr;
    };

    void loop()
    {
        // signal(SIGCHLD, SIG_IGN); // 最好方案直接忽略SIGCHLD信号
        _is_running = true;
        while (_is_running)
        {
            // 4. 获取新连接
            struct sockaddr_in client_addr;
            socklen_t len = sizeof(client_addr);
            int sockfd = ::accept(_listen_sockfd, (struct sockaddr *)&client_addr, &len);
            if (sockfd < 0)
            {
                LOG(WARNING, "accept error!\n");
                continue;
            }
            InetAddr addr(client_addr);
            LOG(INFO, "get a new link, client info %s\n", addr.AddrStr().c_str());

            // Service(sockfd, addr);  --只能单进程

            // 多进程方案
            /* pid_t id = fork();
            if(id == 0)
            {
                // child
                ::close(_listen_sockfd);

                if(fork() > 0) exit(0); //子进程再次创建子进程，让这个孙子进程执行任务，并且子进程结束，孙子进程被系统领养就不需要等待了
                                        // 这个方案可行但不是最佳
                Service(sockfd, addr);
                exit(0);
            }
            ::close(sockfd);


            int n = waitpid(id, nullptr, 0); // 等待会阻塞进程   解决的最佳方案 -- 捕捉SIGCHLD信号并且忽略掉就无需等待
            if(n > 0)
            {
                LOG(INFO, "wait child success!\n");
            } */

            // 多线程方案
            /* pthread_t tid;
            ThreadData *td = new ThreadData(this, sockfd, addr);
            pthread_create(&tid, nullptr, Execute, td); */

            // 线程池方案
            // task_t t = std::bind(&TcpServer::Service, this, sockfd, addr);
            // ThreadPool<task_t>::GetInstance()->Push(t);
            ThreadPool<task_t>::GetInstance()->Push([this, sockfd, addr]()
                                                    { this->Service(sockfd, addr); });
        }
    }

    // 多线程方案 -- 线程执行函数
    /* static void *Execute(void *args)
    {
        pthread_detach(pthread_self()); // 分离线程
        ThreadData *td = static_cast<ThreadData *>(args);
        td->_self->Service(td->_sockfd, td->_addr);
        delete td;
        return nullptr;
    } */

    void Service(int sockfd, InetAddr addr)
    {
        while (true)
        {
            char inbuffer[1024];
            ssize_t n = ::recv(sockfd, inbuffer, sizeof(inbuffer), 0);   // 接收数据
            if (n > 0)
            {
                inbuffer[n] = 0;

                /* std::cout << "[" << addr.AddrStr() << "]# " << inbuffer << std::endl;
                std::string echo_string = "[server echo]# ";
                echo_string += inbuffer; */

                // 调用上层处理函数
                std::string echo_string = _handler(inbuffer);

                ::send(sockfd, echo_string.c_str(), echo_string.size(), 0);    // 发送数据
            }
            else if (n == 0)
            {
                LOG(INFO, "client %s qiut!\n", addr.AddrStr().c_str());
                break;
            }
            else
            {
                LOG(ERROR, "read error: %s\n", addr.AddrStr().c_str());
                break;
            }
        }
        ::close(sockfd);
    }

    ~TcpServer() {}

private:
    uint16_t _port;
    int _listen_sockfd;
    bool _is_running;

    //处理上层任务入口
    handler_t _handler;
};